<template>
  <div>
    <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
      <el-form-item label="部门名称" prop="name">
        <el-input v-model="form.name" />
      </el-form-item>
      <el-form-item label="部门编码" prop="code">
        <el-input v-model="form.code" />
      </el-form-item>
      <el-form-item label="部门负责人" prop="manager">
        <el-select v-model="form.manager" placeholder="请选择活动区域">
          <el-option v-for="item in userList" :key="item.id" :label="item.username" :value="item.username" />
        </el-select>
      </el-form-item>
      <el-form-item label="部门介绍" prop="introduce">
        <el-input v-model="form.introduce" type="textarea" />
      </el-form-item>
      <el-form-item class="btn-bottom">
        <el-button @click="cancel">取消</el-button>
        <el-button type="primary" @click="onSubmit">{{ isEdit ? '点击修改' : '点击创建' }}</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
import { addDepartmentRequest, getDepartmentDetailRequest, updateDepartmentRequest } from '@/api/department'
import { getUserSimpleRequest } from '@/api/employees'
export default {
  props: {
    // 接收父组件传递过来的 pid , 用于作为参数发送 ajax 请求
    currentPid: {
      required: true,
      type: String
    },
    // 用于判断模态框是否为 编辑
    isEdit: {
      required: true,
      type: Boolean
    },
    // * 接收父组件传递的 数组对象, 用来判断用户输入的 数据是否与服务器存在的数据 是否重复
    // * 所有的平铺数据
    arrListToChild: {
      type: Array,
      // 复杂数据类型的默认值, 要用函数调用生成一个新地址
      default: () => []
    }
  },
  data() {
    // 定义一个局部函数: 自定义 部门编码校验
    const validateCode = (rule, value, callback) => {
      // 定义数组 codeList, 将服务器返回的数据中的所有 部门编码 code 存入数组, 用来判断是否重复
      let codeList = this.arrListToChild.map(item => item.code)
      // value 获取到的是 用户输入的 部门编码 code
      // 判断: 如果 value 为空, 代表用户没有输入 部门编码 code
      if (!value) {
        callback(new Error('code 码必填'))
      }
      // 如果是编辑的时候, 当前元素的 code 码, 就不能当做重复数据
      // 因为被人可能就修改一个, 介绍, coode, name 都不改变
      // 这种情况下, code 就不算重读
      if (this.isEdit) {
        codeList = this.arrListToChild.filter(item => item.id !== this.currentPid).map(item => item.code)
      }
      // 如果用户输入的 部门编码 value 在 arrListToChild 数组内包含有, 就证明用户输入的部门编码重复
      if (codeList.includes(value)) {
        callback(new Error(`当前 部门编码 重复: ${value} 值重复`))
      }
      // 如果是自定义校验规则, cakkback()函数必须被调用, 否则这个校验就不会执行
      callback()
    }
    // 自定义部门名称校验
    const validatorName = (rule, value, callback) => {
      // 获取所有部门名称, 筛选出对应部门的子元素
      // 在父组件中, 当我们点击 添加/编辑按钮, 将对应一级菜单的 id 传给子元素, 也就是 currentPid
      // 如果当前元素的 pid 与父元素的 id(currentPid) 相等, 代表该元素是 所点击的父元素的 子元素, 就进行筛选
      // 并将筛选后的 部门名称添加进新数组 nameList
      let nameList = this.arrListToChild.filter(item => item.pid === this.currentPid).map(item => item.name)

      // 如果当前是编辑状态
      // 1. 先找当前元素
      // 2. 找到当前元素所有的兄弟元素
      // 3. 过滤掉当前元素自己
      // == 因为编辑功能校验时, 你所编辑的部门名, 不能和兄弟部门名重名 ==
      // == 而与父级和子集重名不会影响, 并且即便不修改, 和自己原来的名字重复也不影响, 所以也要筛掉自身元素 ==
      // 先找到当前要编辑的元素, currentPid 就是你点击的哪个元素, 就将哪个元素的 id 传到模态框的组件去
      if (this.isEdit) {
        const editParent = this.arrListToChild.find(item => item.id === this.currentPid)
        // 再去找 editParent当前点击元素的所有兄弟元素, 也就是所有 pid 都等于 当前点击的元素的 pid 的元素
        const brother = this.arrListToChild.filter(item => item.pid === editParent.pid)
        // 因为是编辑, 所以最后还要筛选过滤掉当前的被编辑的元素
        nameList = brother.filter(item => item.id !== this.currentPid).map(item => item.name)
      }

      // 判断: 如果筛选后的数组 nameList 数组包含有 用户输入的 部门名称, 就证明用户输入的部门名重复了
      if (nameList.includes(value)) {
        callback(`当前部门名称已存在: ${value}已存在`)
      } else {
        callback()
      }
    }

    return {
      form: {
        name: '',
        code: 0,
        manager: '',
        introduce: ''
      },
      // 部门负责人
      userList: [],
      // 表单校验
      rules: {
        name: [
          { required: true, message: '请输入正确的部门名称', trigger: 'blur' },
          { min: 2, max: 10, message: '长度在 2 ~ 10 个字符', trigger: 'blur' },
          // 自定义校验规则 - 业务校验
          { validator: validatorName, trigger: 'change' }
        ],
        code: [
          // { required: true, message: '请输入正确的部门编码', trigger: 'blur' },
          { min: 2, max: 10, message: '长度在 2 ~ 10 个字符', trigger: 'blur' },
          // 自定义校验规则
          { validator: validateCode, message: '', trigger: 'change' }
        ],
        manager: [
          { required: true, message: '请选择部门负责人', trigger: 'change' }
        ],
        introduce: [
          { required: true, message: '请输入正确格式的部门介绍', trigger: 'blur' },
          { min: 1, max: 300, message: '长度在 1 ~ 300 个字符', trigger: 'blur' }
        ]
      }
    }
  },
  created() {
    // 模态框一开启就调用函数, 获取部门负责人信息
    this.getUserSimple()
    this.getDepartmentDetail()
  },
  methods: {
    // ^ ========== 调用函数发送请求 ==========
    // 获取部门负责人信息
    async getUserSimple() {
      try {
        const res = await getUserSimpleRequest()
        this.userList = res.data
      } catch (err) {
        console.log('获取部门负责人信息失败', err)
      }
    },
    // 获取部门详细信息(编辑功能数据回显)
    async getDepartmentDetail() {
      try {
        if (this.isEdit) { // 如果是编辑, 就进行数据回显
          const res = await getDepartmentDetailRequest(this.currentPid)
          this.form = res?.data
        }
      } catch (err) {
        console.log('获取部门详细信息失败', err)
      }
    },
    // 添加子部门 发送请求
    async addDepertment() {
      try {
        const res = await addDepartmentRequest({ ...this.form, pid: this.currentPid })
        // console.log(res)
        // 判断: 当业务失败怎么做
        // 如果业务代码 成功, 就执行下面逻辑
        // 如果业务代码失败, 就提示一个错误, 不关闭弹窗, 不销毁数据, 让用户修改数据之后重新提交
        if (res.success) {
          this.$message.success('添加部门成功')
          this.$emit('success')
        } else {
          this.$message.error(res.message)
        }
      } catch (err) {
        console.log('添加子部门失败', err)
      }
    },
    // 编辑部门, 发送请求
    async editDepertment() {
      try {
        const res = await updateDepartmentRequest(this.form)
        console.log(res)
        if (res.success) {
          this.$message.success('修改部门信息成功')
          this.$emit('success')
        } else {
          this.$message(res.message)
        }
      } catch (error) {
        console.log('修改部门详情失败', error)
      }
    },
    // ^ ========== 事件处理函数 ==========
    // 新建部门: 点击事件
    onSubmit() {
      // console.log(this.form)
      // 先校验表单是否 通过校验, 再发送请求
      // 通过 $refs 获取 DOM 元素, 要先看获取的是 原生 html 元素, 还是自定义组件
      // 通过 $el 可以找到 el-form 组件对象的 DOM 元素
      // console.log(this.$refs.formRef)
      // 第一个参数 value 表示表单校验是否通过, 获取的是一个布尔值
      // 判断: 如果表单校验通过, 就发送 ajax 请求进行添加修改, 如果不通过就不发送请求
      this.$refs.formRef.validate(value => {
        if (value) {
          if (this.isEdit) { // 如果isEdit 有值代表编辑, 没有代表添加
            this.editDepertment()
          } else {
            this.addDepertment()
          }
          this.$emit('success') // 添加/修改成功, 通知父组件关闭模态框重新渲染数据
        }
      })
    },
    // 取消按钮点击事件: 点击取消按钮, 子组件通知父组件关闭窗口, 将变量设置为 false
    // 因为控制窗口关闭的变量被定义在了父组件中, 并不在子组件内
    cancel() {
      this.$emit('MyCloseEvent')
    }
  }
}
</script>

<style lang="scss">
</style>
